package com.mySpringMvc.web.servlet;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @program: mySSM
 * @description: 处理器执行链
 * @author:wjp
 * @create: 2025-02-13 18:08
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HandlerExecutionChain {
    /**
     * 处理器方法(实际类型为HandlerMethod)
     */
    private Object handler;
    /**
     * 拦截器列表
     */
    private List<HandlerInterceptor> intercepterList;
    /**
     * 拦截器下标（每次拦截器的preHandler方法返回true会进行++，
     * 后续afterCompletion方法只会执行这些preHandler方法返回true的拦截器的afterCompletion方法）
     */
    private int intercepterIndex = -1;

    public boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) {
        // 顺序执行所有的preHandler方法
        for (int i = 0; i < intercepterList.size(); i++) {
            try {
                boolean b = intercepterList.get(i).preHandle(request, response, handler);
                if (!b) {
                    // 如果其中一个preHandler返回false，则执行afterCompletion
                    this.triggerAfterCompletion(request,response,null);
                    return false;
                }
                // 记录返回true的拦截器索引
                this.intercepterIndex = i;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return true;
    }

    public void applyPostHandle(HttpServletRequest request, HttpServletResponse response,ModalAndView mv) {
        // 逆序执行所有的preHandler方法
        for (int i = intercepterList.size() -1 ; i >= 0; i--) {
            try {
                intercepterList.get(i).postHandle(request, response, handler,mv);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,ModalAndView mv) {
        // 倒叙执行返回true的拦截器的afterCompletion方法
        for (int i = this.intercepterIndex; i >= 0; i--) {
            try {
                this.intercepterList.get(i).afterCompletion(request,response,handler,mv);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
